#ifndef __M_FMT_H__
#define __M_FMT_H__

#include "util.hpp"
#include "message.hpp"
#include "level.hpp"
#include <memory>
#include <vector>
#include <tuple>

namespace zdflog
{

    /**
     * @brief 日志格式化项基类
     * 定义了格式化日志消息的接口，所有具体格式化项都继承自此类
     */
    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>; // 智能指针类型定义

        virtual ~FormatItem() {} // 虚析构函数，确保正确释放派生类资源

        /**
         * @brief 纯虚函数，执行格式化操作
         * @param os 输出流，用于写入格式化后的内容
         * @param msg 日志消息对象，包含日志的各种属性
         */
        virtual void format(std::ostream &os, const LogMsg &msg) = 0;
    };

    /**
     * @brief 消息内容格式化项
     * 负责将日志的实际内容部分进行格式化输出
     */
    class MsgFormatItem : public FormatItem
    {
    public:
        MsgFormatItem(const std::string &str = "") {}

        /**
         * @brief 将日志消息的有效载荷写入输出流
         */
        virtual void format(std::ostream &os, const LogMsg &msg)
        {
            os << msg._payload; // 输出日志消息主体内容
        }
    };

    /**
     * @brief 日志级别格式化项
     * 将日志级别转换为可读字符串并输出
     */
    class LevelFormatItem : public FormatItem
    {
    public:
        LevelFormatItem(const std::string &str = "") {}

        /**
         * @brief 将日志级别转换为字符串并写入输出流
         */
        virtual void format(std::ostream &os, const LogMsg &msg)
        {
            os << LogLevel::toString(msg._level); // 将日志级别枚举转换为字符串
        }
    };

    /**
     * @brief 日志器名称格式化项
     * 输出创建该日志的日志器名称
     */
    class NameFormatItem : public FormatItem
    {
    public:
        NameFormatItem(const std::string &str = "") {}

        /**
         * @brief 输出日志器名称
         */
        virtual void format(std::ostream &os, const LogMsg &msg)
        {
            os << msg._name; // 输出日志器名称
        }
    };

    /**
     * @brief 线程ID格式化项
     * 输出日志记录所在的线程ID
     */
    class ThreadFormatItem : public FormatItem
    {
    public:
        ThreadFormatItem(const std::string &str = "") {}

        /**
         * @brief 输出线程ID
         */
        virtual void format(std::ostream &os, const LogMsg &msg)
        {
            os << msg._tid; // 输出线程ID
        }
    };

    /**
     * @brief 时间格式化项
     * 按照指定格式输出日志记录时间
     */
    class TimeFormatItem : public FormatItem
    {
    private:
        std::string _format; // 时间格式字符串

    public:
        /**
         * @brief 构造函数
         * @param format 时间格式字符串，默认为 "%H:%M:%S"
         */
        TimeFormatItem(const std::string &format = "%H:%M:%S") : _format(format)
        {
            if (format.empty())
                _format = "%H:%M:%S"; // 确保格式字符串非空
        }

        /**
         * @brief 按照指定格式输出日志时间
         */
        virtual void format(std::ostream &os, const LogMsg &msg)
        {
            time_t t = msg._ctime; // 获取日志时间戳
            struct tm lt;
            localtime_r(&t, &lt); // 转换为本地时间
            char tmp[128];
            strftime(tmp, 127, _format.c_str(), &lt); // 按照指定格式格式化时间
            os << tmp;
        }
    };

    /**
     * @brief 文件名格式化项
     * 输出日志记录所在的源文件名称
     */
    class CFileFormatItem : public FormatItem
    {
    public:
        CFileFormatItem(const std::string &str = "") {}

        /**
         * @brief 输出文件名
         */
        virtual void format(std::ostream &os, const LogMsg &msg)
        {
            os << msg._file; // 输出文件名
        }
    };

    /**
     * @brief 行号格式化项
     * 输出日志记录在源文件中的行号
     */
    class CLineFormatItem : public FormatItem
    {
    public:
        CLineFormatItem(const std::string &str = "") {}

        /**
         * @brief 输出行号
         */
        virtual void format(std::ostream &os, const LogMsg &msg)
        {
            os << msg._line; // 输出行号
        }
    };

    /**
     * @brief 制表符格式化项
     * 输出一个制表符，用于日志各部分之间的分隔
     */
    class TabFormatItem : public FormatItem
    {
    public:
        TabFormatItem(const std::string &str = "") {}

        /**
         * @brief 输出制表符
         */
        virtual void format(std::ostream &os, const LogMsg &msg)
        {
            os << "\t"; // 输出制表符
        }
    };

    /**
     * @brief 换行符格式化项
     * 输出一个换行符，用于日志记录之间的分隔
     */
    class NLineFormatItem : public FormatItem
    {
    public:
        NLineFormatItem(const std::string &str = "") {}

        /**
         * @brief 输出换行符
         */
        virtual void format(std::ostream &os, const LogMsg &msg)
        {
            os << "\n"; // 输出换行符
        }
    };

    /**
     * @brief 其他字符格式化项
     * 输出固定的字符串内容，用于日志中的静态文本部分
     */
    class OtherFormatItem : public FormatItem
    {
    private:
        std::string _str; // 要输出的字符串

    public:
        OtherFormatItem(const std::string &str = "") : _str(str) {}

        /**
         * @brief 输出固定字符串
         */
        virtual void format(std::ostream &os, const LogMsg &msg)
        {
            os << _str; // 输出固定字符串
        }
    };

    /**
     * @brief 日志格式化器
     * 负责解析格式化模式字符串，并根据模式将日志消息格式化为特定格式
     */
    class Formatter
    {
    public:
        using ptr = std::shared_ptr<Formatter>; // 智能指针类型定义

        /*
            支持的格式化占位符:
            %d 日期时间
            %T 制表符
            %t 线程ID
            %p 日志级别
            %c 日志器名称
            %f 文件名
            %l 行号
            %m 日志消息内容
            %n 换行符
        */
        // 默认格式示例: [时间][线程ID][日志级别][日志器名称][文件名:行号] 日志消息换行
        Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n") : _pattern(pattern)
        {
            assert(parsePattern()); // 解析格式化模式，确保模式合法
        }

        /**
         * @brief 获取当前使用的格式化模式字符串
         * @return 格式化模式字符串
         */
        const std::string pattern() { return _pattern; }

        /**
         * @brief 格式化日志消息为字符串
         * @param msg 日志消息对象
         * @return 格式化后的字符串
         */
        std::string format(const LogMsg &msg)
        {
            std::stringstream ss;
            for (auto &it : _items)
            {
                it->format(ss, msg); // 依次应用每个格式化项
            }
            return ss.str();
        }

        /**
         * @brief 直接将格式化后的日志消息写入输出流
         * @param os 输出流
         * @param msg 日志消息对象
         * @return 输出流引用
         */
        std::ostream &format(std::ostream &os, const LogMsg &msg)
        {
            for (auto &it : _items)
            {
                it->format(os, msg); // 依次应用每个格式化项
            }
            return os;
        }

        /**
         * @brief 根据格式化字符和子格式创建对应的格式化项
         * @param fc 格式化字符(如"m"、"p"等)
         * @param subfmt 子格式字符串(如时间格式)
         * @return 格式化项智能指针
         */
        FormatItem::ptr createItem(const std::string &fc, const std::string &subfmt)
        {
            if (fc == "m")
                return FormatItem::ptr(new MsgFormatItem(subfmt)); // 消息内容
            if (fc == "p")
                return FormatItem::ptr(new LevelFormatItem(subfmt)); // 日志级别
            if (fc == "c")
                return FormatItem::ptr(new NameFormatItem(subfmt)); // 日志器名称
            if (fc == "t")
                return FormatItem::ptr(new ThreadFormatItem(subfmt)); // 线程ID
            if (fc == "n")
                return FormatItem::ptr(new NLineFormatItem(subfmt)); // 换行符
            if (fc == "d")
                return FormatItem::ptr(new TimeFormatItem(subfmt)); // 时间
            if (fc == "f")
                return FormatItem::ptr(new CFileFormatItem(subfmt)); // 文件名
            if (fc == "l")
                return FormatItem::ptr(new CLineFormatItem(subfmt)); // 行号
            if (fc == "T")
                return FormatItem::ptr(new TabFormatItem(subfmt)); // 制表符
            return FormatItem::ptr();                              // 未知格式化字符返回空指针
        }

        /**
         * @brief 解析格式化模式字符串
         * 将模式字符串解析为一系列格式化项，存储在_items中
         * @return 解析成功返回true，失败返回false
         */
        bool parsePattern()
        {
            // 示例模式: "sg{}fsg%d{%H:%M:%S}%Tsdf%t%T[%p]%T[%c]%T%f:%l%T%m%n  "
            // 解析结果存储格式: 每个要素分为三部分(格式化字符, 子格式, 类型)
            // 类型: 0-原始字符串，1-格式化数据

            std::vector<std::tuple<std::string, std::string, int>> arry;
            std::string format_key;        // 存放%后的格式化字符
            std::string format_val;        // 存放格式化字符后边 {} 中的子格式字符串
            std::string string_row;        // 存放原始的非格式化字符
            bool sub_format_error = false; // 子格式错误标志
            int pos = 0;

            // 遍历模式字符串进行解析
            while (pos < _pattern.size())
            {
                // 处理普通字符
                if (_pattern[pos] != '%')
                {
                    string_row.append(1, _pattern[pos++]);
                    continue;
                }

                // 处理转义的% (%%)
                if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%')
                {
                    string_row.append(1, '%');
                    pos += 2;
                    continue;
                }

                // 将已收集的普通字符串添加到解析结果
                if (string_row.empty() == false)
                {
                    arry.push_back(std::make_tuple(string_row, "", 0));
                    string_row.clear();
                }

                // 当前位置是%字符，处理格式化占位符
                pos += 1; // pos指向格式化字符位置

                // 检查是否为合法的格式化字符
                if (pos < _pattern.size() && isalpha(_pattern[pos]))
                {
                    format_key = _pattern[pos]; // 保存格式化字符
                }
                else
                {
                    std::cout << &_pattern[pos - 1] << "位置附近格式错误！\n";
                    return false;
                }

                // 处理可能的子格式 (如%d{%Y-%m-%d})
                pos += 1; // pos指向格式化字符的下一个位置
                if (pos < _pattern.size() && _pattern[pos] == '{')
                {
                    sub_format_error = true;
                    pos += 1; // pos指向花括号下一个字符处

                    // 收集子格式内容
                    while (pos < _pattern.size())
                    {
                        if (_pattern[pos] == '}')
                        {
                            sub_format_error = false;
                            pos += 1; // 让pos指向}的下一个字符处
                            break;
                        }
                        format_val.append(1, _pattern[pos++]);
                    }
                }

                // 将解析出的格式化项添加到结果
                arry.push_back(std::make_tuple(format_key, format_val, 1));
                format_key.clear();
                format_val.clear();
            }

            // 检查子格式是否正确闭合
            if (sub_format_error)
            {
                std::cout << "{}对应出错\n";
                return false;
            }

            // 将剩余的字符串添加到解析结果
            if (string_row.empty() == false)
                arry.push_back(std::make_tuple(string_row, "", 0));
            if (format_key.empty() == false)
                arry.push_back(std::make_tuple(format_key, format_val, 1));

            // 根据解析结果创建格式化项对象
            for (auto &it : arry)
            {
                if (std::get<2>(it) == 0)
                {
                    // 普通字符串
                    FormatItem::ptr fi(new OtherFormatItem(std::get<0>(it)));
                    _items.push_back(fi);
                }
                else
                {
                    // 格式化项
                    FormatItem::ptr fi = createItem(std::get<0>(it), std::get<1>(it));
                    if (fi.get() == nullptr)
                    {
                        std::cout << "没有对应的格式化字符: %" << std::get<0>(it) << std::endl;
                        return false;
                    }
                    _items.push_back(fi);
                }
            }

            return true;
        }

    private:
        std::string _pattern;                // 格式化模式字符串
        std::vector<FormatItem::ptr> _items; // 格式化项列表
    };
}
#endif